import os
import sys
import common
import time
import dao
import json
from typing import *
from flask import Flask
from flask import request
app = Flask(__name__)
users = {}   #保存用户的任务范围
config = {}  #保存参数信息

def construct_univeral_return_obj(data:Union[str, Dict, List]):
    """统计的响应对象"""
    if isinstance(data, str):
        return json.dumps({"status": False, "msg": data}, ensure_ascii=False)
    else:
        return json.dumps({"status": True, "data": data}, ensure_ascii=False)


@app.route('/task/<username>')   #此接口随机获取一个任务
def task(username):
    if(not username in users.keys()):
        return construct_univeral_return_obj("错误的访问")
    user = users[username]
    start, end = user["range"]
    daoImpl = dao.DAOImpl(config["db_name"])
    row = daoImpl.select_row_by_range(config["tb_name"], config["state"], config["index"], start, end)
    if not (row is None):
        obj = {}
        obj["id"] = row[config["index"]]
        obj["text"] = row[config["text"]]
        obj["columns"] = config["task_columns"]
        obj["labels"] = config["task_labels"]
        obj["labels_ids"] = []
        for task_column in config["task_columns"]:
            obj["labels_ids"].append(row[task_column])
        obj["finished"] = daoImpl.select_row_finished(config["tb_name"], config["state"], config["index"], start, end)[0]
        obj["total"] = end - start
        obj["token"] = common.generate_identifier(1, 10)[0]
        user["token"]["id"] = obj["token"]
        user["token"]["time"] = time.time()
        return construct_univeral_return_obj(obj)
    else:
        return construct_univeral_return_obj("已经标注完成了所有的记录")

@app.route("/finish/<username>/<int:id>")  #此接口完成一个任务
def finish(username, id):
    if (not username in users.keys()):
        return construct_univeral_return_obj("错误的访问")
    user = users[username]
    start, end = user["range"]
    if(id <= start or id > end):
        return construct_univeral_return_obj("横向越权")

    #print(user) #delete
    token = request.args.get("token", "")
    if token != user["token"]["id"]:
        return construct_univeral_return_obj("token错误")

    time_waste = time.time() - user["token"]["time"]
    if(time_waste < 0.5):
        return construct_univeral_return_obj("你请求动作太快啦！")

    tasks = {}
    try:
        for i in range(len(config["task_columns"])):
            task_column =  config["task_columns"][i]
            tasks[task_column] =  int(request.args.get(task_column, ""))
            if tasks[task_column] < 0 or tasks[task_column] >= len(config["task_labels"][i]):
                raise RuntimeError("任务参数范围有误")
    except:
        return construct_univeral_return_obj("任务参数传递有误")

    #更新记录
    daoImpl = dao.DAOImpl(config["db_name"])
    updated_list = []
    for key, value in tasks.items():
        update_result = daoImpl.update_a_row(config["tb_name"], config["index"], id, key, value)
        updated_list.append(update_result)
    #print(updated_list)
    status = 2 if any(updated_list) else 1
    daoImpl.update_a_row(config["tb_name"], config["index"], id, config["state"], status)
    return construct_univeral_return_obj({"info": "更新成功"})


@app.route("/progress/<username>") #此接口返回任务完成的情况
def progress(username):
    if username != config["admin"]:
        return construct_univeral_return_obj("非法访问")
    response_obj = []
    daoImpl = dao.DAOImpl(config["db_name"])
    for user_identifier, user in users.items():
        start, end = user["range"]
        user_finished_num, user_updated_num = daoImpl.select_row_finished(config["tb_name"], config["state"], config["index"], start, end)
        response_obj.append({"id": user_identifier, "finished": user_finished_num, "updated": user_updated_num, "total": end - start})
    return construct_univeral_return_obj(response_obj)


if __name__ == "__main__":
    if(len(sys.argv) < 5):
        common.print_cmd()
    #参数的输入
    db_name = sys.argv[1]
    tb_name = sys.argv[2]
    tasks_columns = sys.argv[3]
    tasks_labels = sys.argv[4]
    options = {}
    for i in range(5, len(sys.argv)):
        try:
            key, value = sys.argv[i].split("=", maxsplit=2)
        except:
            common.print_cmd()
        options[key] = value
    #print(options)

    #参数的判断
    if(not common.is_db_awailable(db_name)):
        common.exit_with_msg("无效的sqlite数据库: %s"%(db_name,))
    if(not common.is_tb_awailable(db_name, tb_name)):
        common.exit_with_msg("无效的sqlite表: %s"%(tb_name,))
    tasks_columns_list:List = tasks_columns.split(";")
    tasks_labels_list:List = tasks_labels.split(";")
    for i in range(len(tasks_labels_list)):
        tasks_labels_list[i] = tasks_labels_list[i].split(",")
    #print(tasks_columns_list)
    #print(tasks_labels_list)
    if(len(tasks_columns_list) != len(tasks_labels_list)):
        common.exit_with_msg("任务数量和标签不匹配")

    for task_name in tasks_columns_list:
        if(not common.is_col_awailable(db_name, tb_name, task_name)):
            common.exit_with_msg("sqlite中不存在列名：%s"%(task_name, ))

    try:
        options["--worker"] = (int(options.get("--worker"))) if not options.get("--worker") is None else 1
        options["--text"] = options.get("--text") if not options.get("--text") is None else "sentence"
        options["--state"] = options.get("--state") if not options.get("--state") is None else "status"
        options["--index"] = options.get("--index") if not options.get("--index") is None else "id"
        options["--port"] = options.get("--port") if not options.get("--port") is None else 8080
    except:
        common.print_cmd()

    if (not common.is_col_awailable(db_name, tb_name, options["--text"])):
        common.exit_with_msg("sqlite中不存在列名：%s" % (options["--text"], ) )
    if (not common.is_col_awailable(db_name, tb_name, options["--state"])):
        common.exit_with_msg("sqlite中不存在列名：%s" % (options["--state"], ))
    if (not common.is_col_awailable(db_name, tb_name, options["--index"])):
        common.exit_with_msg("sqlite中不存在列名：%s" % (options["--index"], ))

    #保存参数
    config["db_name"] = db_name
    config["tb_name"] = tb_name
    config["task_columns"] = tasks_columns_list
    config["task_labels"] = tasks_labels_list
    config["worker"] = options["--worker"]
    config["text"] = options["--text"]
    config["state"] = options["--state"]
    config["index"] = options["--index"]
    config["admin"] = common.generate_identifier(1, 10)[0]
    #print(config)

    #计算各个用户负者的任务范围
    text_row_count = common.get_row_count(db_name, tb_name)
    text_row_ranges = common.get_ranges(text_row_count, options["--worker"])
    identifiers = common.generate_identifier(options["--worker"], 8)
    for i in range(len(text_row_ranges)):
        users[identifiers[i]] = {'range':  text_row_ranges[i], 'token': {'id': common.generate_identifier(1, 10)[0], 'time':  time.time()}}
    print('初始化完毕')

    #运行程序
    print("请通过以下链接完成标注任务：")
    current_ip = common.get_current_ip()
    for i in range(len(text_row_ranges)):
        print("http://%s:%s/static/index.html?identifier=%s"%(current_ip, options["--port"], identifiers[i]))
    print("查看任务进度路径：")
    print("http://%s:%s/static/progress.html?identifier=%s"%(current_ip, options["--port"], config["admin"]))
    app.run("0.0.0.0", options["--port"])

